home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / term-source.lha / Extras / Source / term-Source.lha / Chat.c < prev    next >
C/C++ Source or Header  |  1995-02-13  |  14KB  |  708 lines

  1. /*
  2. **    Chat.c
  3. **
  4. **    Chat support code
  5. **
  6. **    Copyright © 1990-1995 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     // Maximum number of characters to enter per line
  13.  
  14. #define CHAT_LINE_SIZE    512
  15.  
  16.     // Local data
  17.  
  18. STATIC struct List    *ChatList;
  19. STATIC struct Node    *ChatNode;
  20. STATIC STRPTR         ChatBuffer,
  21.              ChatUndo,
  22.              ChatWork,
  23.              ChatTemp;
  24. STATIC LONG         ChatPosition;
  25. STATIC Object        *ChatGadget;
  26. STATIC struct Hook     ChatHook = { {NULL},(HOOKFUNC)ChatKey };
  27. STATIC BOOL         ChatWasActive;
  28.  
  29.     /* ChatKey(register __a1 ULONG *Msg,register __a2 struct SGWork *Work):
  30.      *
  31.      *    String gadget editing hook code. This is where all the
  32.      *    magic happens.
  33.      */
  34.  
  35. ULONG __saveds __asm
  36. ChatKey(register __a1 ULONG *Msg,register __a2 struct SGWork *Work)
  37. {
  38.         /* Someone activated the string gadget and
  39.          * hit a key.
  40.          */
  41.  
  42.     if(*Msg == SGH_KEY)
  43.     {
  44.         BOOL    NeedChange    = FALSE,
  45.             DidSomething    = FALSE;
  46.  
  47.             // Remember that this gadget was activated
  48.  
  49.         Forbid();
  50.  
  51.         ChatWasActive = TRUE;
  52.  
  53.         Permit();
  54.  
  55.             // Clear the history list when pressing Amiga+Del/Amiga+Backspace
  56.  
  57.         if((Work -> IEvent -> ie_Qualifier & (AMIGARIGHT | AMIGALEFT)) && (Work -> IEvent -> ie_Code == DEL_CODE || Work -> IEvent -> ie_Code == BACKSPACE_CODE))
  58.         {
  59.             FreeList(ChatList);
  60.  
  61.             NewList(ChatList);
  62.  
  63.             ChatNode = NULL;
  64.  
  65.             Work -> Actions &= ~(SGA_USE | SGA_BEEP);
  66.  
  67.             return(TRUE);
  68.         }
  69.  
  70.             /* Right-Amiga-key was pressed, release the
  71.              * string gadget so user may select a menu
  72.              * item.
  73.              */
  74.  
  75.         if((Work -> IEvent -> ie_Qualifier & AMIGARIGHT) && Work -> IEvent -> ie_Code < 96)
  76.         {
  77.             if(!(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) && (Work -> IEvent -> ie_Code == KEYCODE_X || Work -> IEvent -> ie_Code == KEYCODE_Q))
  78.                 return(TRUE);
  79.             else
  80.             {
  81.                 Work -> Actions = (Work -> Actions & ~(SGA_USE | SGA_BEEP)) | SGA_END | SGA_REUSE;
  82.  
  83.                 return(TRUE);
  84.             }
  85.         }
  86.  
  87.             // This looks like a function key. Send the corresponding macro.
  88.  
  89.         if(Work -> IEvent -> ie_Code >= F01_CODE && Work -> IEvent -> ie_Code <= F10_CODE)
  90.         {
  91.             STRPTR    String;
  92.             LONG    Len,Index = Work -> IEvent -> ie_Code - F01_CODE;
  93.  
  94.             Forbid();
  95.  
  96.                 // Pick the right macro
  97.  
  98.             if(Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL)
  99.                 String = MacroKeys -> Keys[3][Index];
  100.             else
  101.             {
  102.                 if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
  103.                     String = MacroKeys -> Keys[2][Index];
  104.                 else
  105.                 {
  106.                     if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  107.                         String = MacroKeys -> Keys[1][Index];
  108.                     else
  109.                         String = MacroKeys -> Keys[0][Index];
  110.                 }
  111.             }
  112.  
  113.                 // Anything to send at all?
  114.  
  115.             if(Len = strlen(String))
  116.             {
  117.                 struct DataMsg *Msg;
  118.  
  119.                 if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg) + Len + 1))
  120.                 {
  121.                     Msg -> Type = DATAMSGTYPE_SERIALCOMMAND;
  122.                     Msg -> Data = (STRPTR)(Msg + 1);
  123.  
  124.                     strcpy(Msg -> Data,String);
  125.  
  126.                         // Send the command
  127.  
  128.                     PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
  129.                 }
  130.             }
  131.  
  132.             Permit();
  133.  
  134.             return(TRUE);
  135.         }
  136.  
  137.             /* The user pressed the cursor-right key to
  138.              * move the cursor to the next word in the buffer.
  139.              */
  140.  
  141.         if(Work -> IEvent -> ie_Code == CURSORRIGHT && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL))
  142.         {
  143.             if(Work -> BufferPos != Work -> NumChars)
  144.             {
  145.                 WORD i,Position = -1;
  146.  
  147.                 for(i = Work -> BufferPos ; i < Work -> NumChars ; i++)
  148.                 {
  149.                     if(Work -> WorkBuffer[i] == ' ')
  150.                     {
  151.                         for( ; i < Work -> NumChars ; i++)
  152.                         {
  153.                             if(Work -> WorkBuffer[i] != ' ')
  154.                             {
  155.                                 Position = i;
  156.                                 break;
  157.                             }
  158.                         }
  159.  
  160.                         break;
  161.                     }
  162.                 }
  163.  
  164.                 if(Position != -1)
  165.                     Work -> BufferPos = Position;
  166.                 else
  167.                     Work -> BufferPos = Work -> NumChars;
  168.  
  169.                 Work -> EditOp = EO_MOVECURSOR;
  170.             }
  171.  
  172.             return(TRUE);
  173.         }
  174.  
  175.             /* The user pressed the cursor-right key to
  176.              * move the cursor to the previous word in the buffer.
  177.              */
  178.  
  179.         if(Work -> IEvent -> ie_Code == CURSORLEFT && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL))
  180.         {
  181.             if(Work -> BufferPos)
  182.             {
  183.                 WORD i,Position = -1;
  184.  
  185.                 for(i = Work -> BufferPos ; i >= 0 ; i--)
  186.                 {
  187.                     if(Work -> WorkBuffer[i] != ' ')
  188.                     {
  189.                         Position = i;
  190.                         break;
  191.                     }
  192.                 }
  193.  
  194.                 if(Position == -1)
  195.                     Position = 0;
  196.  
  197.                 if(Position)
  198.                 {
  199.                     i = Position;
  200.  
  201.                     Position = -1;
  202.  
  203.                     for( ; i >= 0 ; i--)
  204.                     {
  205.                         if(Work -> WorkBuffer[i] == ' ')
  206.                         {
  207.                             Position = i + 1;
  208.                             break;
  209.                         }
  210.                     }
  211.                 }
  212.  
  213.                 if(Position != -1)
  214.                     Work -> BufferPos = Position;
  215.                 else
  216.                     Work -> BufferPos = 0;
  217.  
  218.                 Work -> EditOp = EO_MOVECURSOR;
  219.             }
  220.  
  221.             DidSomething = TRUE;
  222.         }
  223.  
  224.             /* The user pressed the cursor-up key to
  225.              * scroll through the command history.
  226.              */
  227.  
  228.         if(Work -> IEvent -> ie_Code == CURSORUP)
  229.         {
  230.                 /* Shift key: jump to first command
  231.                  * history entry.
  232.                  */
  233.  
  234.             if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  235.             {
  236.                 if(ChatList -> lh_Head -> ln_Succ)
  237.                     ChatNode = ChatList -> lh_Head;
  238.                 else
  239.                     ChatNode = NULL;
  240.  
  241.                 NeedChange = TRUE;
  242.             }
  243.             else
  244.             {
  245.                 if(ChatNode)
  246.                 {
  247.                     if(ChatNode -> ln_Pred -> ln_Pred)
  248.                     {
  249.                         ChatNode = ChatNode -> ln_Pred;
  250.  
  251.                         NeedChange = TRUE;
  252.                     }
  253.                 }
  254.                 else
  255.                 {
  256.                     if(ChatList -> lh_Head -> ln_Succ)
  257.                     {
  258.                         ChatNode = ChatList -> lh_TailPred;
  259.  
  260.                         NeedChange = TRUE;
  261.                     }
  262.                 }
  263.             }
  264.  
  265.             DidSomething = TRUE;
  266.         }
  267.  
  268.             /* The user pressed the cursor-down key to
  269.              * scroll through the command history.
  270.              */
  271.  
  272.         if(Work -> IEvent -> ie_Code == CURSORDOWN)
  273.         {
  274.                 /* Shift key: jump to last command
  275.                  * history entry.
  276.                  */
  277.  
  278.             if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  279.             {
  280.                 if(ChatList -> lh_Head -> ln_Succ)
  281.                     ChatNode = ChatList -> lh_TailPred;
  282.                 else
  283.                     ChatNode = NULL;
  284.  
  285.                 NeedChange = TRUE;
  286.             }
  287.             else
  288.             {
  289.                 if(ChatNode)
  290.                 {
  291.                     if(ChatNode -> ln_Succ -> ln_Succ)
  292.                         ChatNode = ChatNode -> ln_Succ;
  293.                     else
  294.                         ChatNode = NULL;
  295.                 }
  296.  
  297.                 NeedChange = TRUE;
  298.             }
  299.  
  300.             DidSomething = TRUE;
  301.         }
  302.  
  303.             // Update the contents of the string gadget
  304.  
  305.         if(NeedChange)
  306.         {
  307.             LONG Len;
  308.  
  309.             if(ChatNode)
  310.                 strcpy(Work -> WorkBuffer,ChatNode -> ln_Name);
  311.             else
  312.                 Work -> WorkBuffer[0] = 0;
  313.  
  314.             strcpy(Work -> StringInfo -> UndoBuffer,Work -> PrevBuffer);
  315.  
  316.             Work -> StringInfo -> UndoPos = Work -> BufferPos;
  317.  
  318.             Len = strlen(Work -> WorkBuffer);
  319.  
  320.             if(Len < Work -> BufferPos)
  321.                 Work -> BufferPos = Len;
  322.  
  323.             Work -> NumChars    = Len;
  324.             Work -> Actions        = (Work -> Actions & ~SGA_BEEP) | SGA_USE | SGA_REDISPLAY;
  325.         }
  326.  
  327.             // User pressed return?
  328.  
  329.         if(Work -> Actions & SGA_END)
  330.         {
  331.                 // Deactivate the gadget?
  332.  
  333.             if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  334.             {
  335.                 Work -> Actions &= ~SGA_END;
  336.  
  337.                 Forbid();
  338.  
  339.                 ChatWasActive = FALSE;
  340.  
  341.                 Permit();
  342.             }
  343.             else
  344.             {
  345.                 struct DataMsg    *Msg;
  346.                 LONG         Len = Work -> NumChars;
  347.  
  348.                     // If any text was entered, add it to the history list
  349.  
  350.                 if(Work -> WorkBuffer[0])
  351.                 {
  352.                     BOOL AddIt = TRUE;
  353.  
  354.                         // Don't add duplicates
  355.  
  356.                     if(ChatNode)
  357.                     {
  358.                         if(!Stricmp(ChatNode -> ln_Name,Work -> WorkBuffer))
  359.                             AddIt = FALSE;
  360.                     }
  361.  
  362.                         // Allocate space for the text, then add it
  363.  
  364.                     if(AddIt)
  365.                     {
  366.                         struct Node *SomeNode;
  367.  
  368.                         if(SomeNode = (struct Node *)AllocVecPooled(sizeof(struct Node) + Len + 1,MEMF_ANY))
  369.                         {
  370.                             strcpy(SomeNode -> ln_Name = (STRPTR)(SomeNode + 1),Work -> WorkBuffer);
  371.  
  372.                             AddTail(ChatList,SomeNode);
  373.                         }
  374.                     }
  375.                 }
  376.  
  377.                 ChatNode = NULL;
  378.  
  379.                     // Transfer the buffer
  380.  
  381.                 if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg) + Len + 3))
  382.                 {
  383.                     STRPTR Extra;
  384.  
  385.                     Msg -> Type = DATAMSGTYPE_SERIALCOMMAND;
  386.                     Msg -> Data = (STRPTR)(Msg + 1);
  387.  
  388.                     strcpy(Msg -> Data,Work -> WorkBuffer);
  389.  
  390.                         // Add EOL characters
  391.  
  392.                     switch(Config -> TerminalConfig -> SendCR)
  393.                     {
  394.                         case EOL_CR:
  395.  
  396.                             Extra = "\r";
  397.                             break;
  398.  
  399.                         case EOL_LF:
  400.  
  401.                             Extra = "\n";
  402.                             break;
  403.  
  404.                         case EOL_CRLF:
  405.  
  406.                             Extra = "\r\n";
  407.                             break;
  408.  
  409.                         case EOL_LFCR:
  410.  
  411.                             Extra = "\n\r";
  412.                             break;
  413.  
  414.                         default:
  415.  
  416.                             Extra = NULL;
  417.                             break;
  418.                     }
  419.  
  420.                     if(Extra)
  421.                         strcpy(Msg -> Data + Len,Extra);
  422.  
  423.                         // Clear the string gadget
  424.  
  425.                     Work -> WorkBuffer[0]    = 0;
  426.                     Work -> BufferPos    = 0;
  427.                     Work -> NumChars    = 0;
  428.                     Work -> Actions        = (Work -> Actions & ~(SGA_BEEP | SGA_END)) | SGA_USE | SGA_REDISPLAY;
  429.  
  430.                     Work -> StringInfo -> UndoPos        = 0;
  431.                     Work -> StringInfo -> UndoBuffer[0]    = 0;
  432.  
  433.                         // Send the line
  434.  
  435.                     PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
  436.                 }
  437.             }
  438.  
  439.             DidSomething = TRUE;
  440.         }
  441.  
  442.             // Control character entered?
  443.  
  444.         if(!DidSomething && Work -> Code && !(Work -> Code & 0xFFE0))
  445.         {
  446.             UBYTE Code = Work -> Code & 0x1F;
  447.  
  448.             if(Code == '\t' && Work -> IEvent -> ie_Code != TAB_CODE)
  449.                 return(TRUE);
  450.  
  451.             if(Code != '\r' && Code != '\b')
  452.             {
  453.                 struct DataMsg *Msg;
  454.  
  455.                 if(Code == ('S' & 0x1F) || Code == ('Q' & 0x1F))
  456.                 {
  457.                     if(Config -> SerialConfig -> xONxOFF)
  458.                     {
  459.                         Forbid();
  460.  
  461.                         if(Code == ('S' & 0x1F))
  462.                         {
  463.                             if(Status == STATUS_READY)
  464.                                 Status = STATUS_HOLDING;
  465.                         }
  466.                         else
  467.                         {
  468.                             if(Status == STATUS_HOLDING)
  469.                                 Status = STATUS_READY;
  470.                         }
  471.  
  472.                         Permit();
  473.                     }
  474.  
  475.                     if(!Config -> SerialConfig -> PassThrough)
  476.                         return(TRUE);
  477.                 }
  478.  
  479.                 if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg) + 2))
  480.                 {
  481.                     Work -> Actions &= ~SGA_USE;
  482.  
  483.                     Msg -> Type = DATAMSGTYPE_SERIALCOMMAND;
  484.                     Msg -> Data = (STRPTR)(Msg + 1);
  485.  
  486.                     Msg -> Data[0] = Code;
  487.                     Msg -> Data[1] = 0;
  488.  
  489.                     PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
  490.                 }
  491.             }
  492.         }
  493.  
  494.         return(TRUE);
  495.     }
  496.     else
  497.     {
  498.         if(*Msg == SGH_CLICK)
  499.         {
  500.                 // Remember activation
  501.  
  502.             Forbid();
  503.  
  504.             ChatWasActive = TRUE;
  505.  
  506.             Permit();
  507.  
  508.             return(TRUE);
  509.         }
  510.         else
  511.             return(FALSE);
  512.     }
  513. }
  514.  
  515.     /* HideChatGadget():
  516.      *
  517.      *    Remove the chat gadget, but don't free the buffers.
  518.      */
  519.  
  520. VOID
  521. HideChatGadget()
  522. {
  523.     if(ChatGadget)
  524.     {
  525.         GetAttr(STRINGA_BufferPos,ChatGadget,(ULONG *)&ChatPosition);
  526.  
  527.         RemoveGList(Window,(struct Gadget *)ChatGadget,1);
  528.  
  529.         DisposeObject(ChatGadget);
  530.  
  531.         ChatGadget = NULL;
  532.     }
  533. }
  534.  
  535.     /* DeleteChatGadget():
  536.      *
  537.      *    Remove the chat gadget, also take care of the buffers.
  538.      */
  539.  
  540. VOID
  541. DeleteChatGadget()
  542. {
  543.     HideChatGadget();
  544.  
  545.     if(ChatBuffer)
  546.     {
  547.         FreeVecPooled(ChatBuffer);
  548.  
  549.         ChatBuffer = NULL;
  550.     }
  551.  
  552.     if(ChatList)
  553.     {
  554.         DeleteList(ChatList);
  555.  
  556.         ChatList = NULL;
  557.     }
  558. }
  559.  
  560.     /* UpdateChatGadget():
  561.      *
  562.      *    Redraw the chat gadget imagery.
  563.      */
  564.  
  565. VOID
  566. UpdateChatGadget()
  567. {
  568.     if(ChatGadget)
  569.     {
  570.         struct RastPort    *RPort = Window -> RPort;
  571.         LONG         Left,Right,Top;
  572.  
  573.             // Draw the separator bar
  574.  
  575.         if(StatusWindow || Config -> ScreenConfig -> StatusLine == STATUSLINE_DISABLED)
  576.             Top = UserFontHeight;
  577.         else
  578.             Top = StatusDisplayHeight + UserFontHeight;
  579.  
  580.         Top    = Window -> Height - (Window -> BorderBottom + Top + 2);
  581.         Left    = Window -> BorderLeft;
  582.         Right    = Window -> Width - (Window -> BorderRight + 1);
  583.  
  584.         SetAPen(RPort,DrawInfo -> dri_Pens[SHADOWPEN]);
  585.         Move(RPort,Left,Top);
  586.         Draw(RPort,Right,Top);
  587.  
  588.         Top++;
  589.  
  590.         SetAPen(RPort,DrawInfo -> dri_Pens[SHINEPEN]);
  591.         Move(RPort,Left,Top);
  592.         Draw(RPort,Right,Top);
  593.  
  594.             // Redraw the gadget
  595.  
  596.         RefreshGList((struct Gadget *)ChatGadget,Window,NULL,1);
  597.     }
  598. }
  599.  
  600.     /* ActivateChat(BOOL Reactivate):
  601.      *
  602.      *    Activate the chat gadget.
  603.      */
  604.  
  605. VOID __regargs
  606. ActivateChat(BOOL Reactivate)
  607. {
  608.     if(ChatGadget)
  609.     {
  610.         Forbid();
  611.  
  612.         if(Reactivate)
  613.             Reactivate = ChatWasActive;
  614.         else
  615.             Reactivate = TRUE;
  616.  
  617.         Permit();
  618.  
  619.         if(Reactivate)
  620.             ActivateGadget((struct Gadget *)ChatGadget,Window,NULL);
  621.     }
  622. }
  623.  
  624.     /* CreateChatGadget():
  625.      *
  626.      *    Create the chat gadget and add it to the main window.
  627.      */
  628.  
  629. BOOL
  630. CreateChatGadget()
  631. {
  632.     ChatWasActive = TRUE;
  633.  
  634.         // Allocate the history list
  635.  
  636.     if(!ChatList)
  637.     {
  638.         if(!(ChatList = (struct List *)AllocVecPooled(sizeof(struct MinList),MEMF_ANY)))
  639.             return(FALSE);
  640.         else
  641.             NewList(ChatList);
  642.  
  643.         ChatNode = NULL;
  644.     }
  645.  
  646.         // Allocate the undo/work/editing buffers
  647.  
  648.     if(!ChatBuffer)
  649.     {
  650.         if(!(ChatBuffer = (STRPTR)AllocVecPooled(5 * CHAT_LINE_SIZE,MEMF_ANY | MEMF_CLEAR)))
  651.         {
  652.             DeleteChatGadget();
  653.  
  654.             return(FALSE);
  655.         }
  656.         else
  657.         {
  658.             ChatUndo = ChatBuffer    + CHAT_LINE_SIZE;
  659.             ChatWork = ChatUndo    + CHAT_LINE_SIZE;
  660.             ChatTemp = ChatWork    + CHAT_LINE_SIZE;
  661.         }
  662.     }
  663.  
  664.         // Finally create the gadget
  665.  
  666.     if(!ChatGadget)
  667.     {
  668.         LONG Bottom = Window -> BorderBottom + UserFontHeight - 1;
  669.  
  670.         if(!StatusWindow && Config -> ScreenConfig -> StatusLine != STATUSLINE_DISABLED && !Config -> ScreenConfig -> SplitStatus)
  671.             Bottom += StatusDisplayHeight;
  672.  
  673.         if(!(ChatGadget = NewObject(NULL,STRGCLASS,
  674.             GA_Left,        Window -> BorderLeft,
  675.             GA_Height,        UserFontHeight,
  676.             GA_RelBottom,        -Bottom,
  677.             GA_RelWidth,        -(Window -> BorderLeft + Window -> BorderRight),
  678.             GA_TabCycle,        FALSE,
  679.             STRINGA_TextVal,    ChatBuffer,
  680.             STRINGA_MaxChars,    CHAT_LINE_SIZE,
  681.             STRINGA_Buffer,        ChatBuffer,
  682.             STRINGA_BufferPos,    ChatPosition,
  683.             STRINGA_UndoBuffer,    ChatUndo,
  684.             STRINGA_WorkBuffer,    ChatWork,
  685.             STRINGA_NoFilterMode,    TRUE,
  686.  
  687.                 // NOTE: This should really look like below,
  688.                 //       according to the BOOPSI documentation.
  689.  
  690. //            STRINGA_Pens,        ((LONG)DrawInfo -> dri_Pens[BACKGROUNDPEN] << 16) | DrawInfo -> dri_Pens[TEXTPEN],
  691. //            STRINGA_ActivePens,    ((LONG)DrawInfo -> dri_Pens[BACKGROUNDPEN] << 16) | DrawInfo -> dri_Pens[TEXTPEN],
  692.  
  693.             STRINGA_Pens,        ((LONG)DrawInfo -> dri_Pens[BACKGROUNDPEN] << 8) | DrawInfo -> dri_Pens[TEXTPEN],
  694.             STRINGA_ActivePens,    ((LONG)DrawInfo -> dri_Pens[BACKGROUNDPEN] << 8) | DrawInfo -> dri_Pens[TEXTPEN],
  695.             STRINGA_EditHook,    &ChatHook,
  696.         TAG_DONE)))
  697.         {
  698.             DeleteChatGadget();
  699.  
  700.             return(FALSE);
  701.         }
  702.         else
  703.             AddGList(Window,(struct Gadget *)ChatGadget,(UWORD)~0,1,NULL);
  704.     }
  705.  
  706.     return(TRUE);
  707. }
  708.